package  
{
	import flash.display.CapsStyle;
	import flash.display.GradientType;
	import flash.display.GraphicsEndFill;
	import flash.display.GraphicsGradientFill;
	import flash.display.GraphicsPath;
	import flash.display.GraphicsPathCommand;
	import flash.display.GraphicsPathWinding;
	import flash.display.GraphicsSolidFill;
	import flash.display.GraphicsStroke;
	import flash.display.IGraphicsData;
	import flash.display.JointStyle;
	import flash.geom.Matrix;
	import flash.geom.Point;
	/**
	 * ...
	 * @author Lorenzo Nuvoletta
	 */
	public class CairoParser 
	{
		
		public static const GRADIENT_CONST:Number = 1638.4;
		public static const TWO_THIRD:Number = 2 / 3;
		
		private var _type:int;
		
		public function CairoParser(v:Vector.<IGraphicsData>) 
		{			
			trace("\nTRACING CODE:\n");
			
			trace( "cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 300);" );
			trace( "cairo_t *cr = cairo_create(surface);" );
			trace( "cairo_pattern_t *pat;" );
			
			for (var i:int = 0; i < v.length; i++) {				
				if (v[i] is GraphicsSolidFill) {
					_type = VectorGraphics.TYPE_GraphicsSolidFill;
					var gsf:GraphicsSolidFill = GraphicsSolidFill(v[i]);
					trace("cairo_set_source_rgba(cr," + String(redPercent(gsf.color)) +"," + String(greenPercent(gsf.color)) +"," + String(bluePercent(gsf.color)) +"," + gsf.alpha + ");");
				}
				else if (v[i] is GraphicsGradientFill) {
					_type = VectorGraphics.TYPE_GraphicsGradientFill;
					var grad:GraphicsGradientFill = GraphicsGradientFill(v[i]);
					
					var rot:Number = Math.atan(grad.matrix.b / grad.matrix.a);
					if (grad.matrix.a < 0) {
						rot += Math.PI;
					}
					var cos:Number = Math.cos( rot );
					var sin:Number = Math.sin( rot );
					
					var w:Number = (grad.matrix.a / cos ) * GRADIENT_CONST;
					var h:Number = (-grad.matrix.c / sin ) * GRADIENT_CONST;								
					
					if (grad.type == GradientType.LINEAR) {
						var halfWCos:Number = (w / 2) * cos;
						var halfHSin:Number = (h / 2) * sin;
					
						var leftPoint:Point = new Point(grad.matrix.tx - halfWCos, grad.matrix.ty - halfHSin);
						var rightPoint:Point = new Point(grad.matrix.tx + halfWCos, grad.matrix.ty + halfHSin);
					
						trace( "pat = cairo_pattern_create_linear("+leftPoint.x+","+ leftPoint.y+","+ rightPoint.x+","+ rightPoint.y+");" );
					}
					else {
						trace( "pat = cairo_pattern_create_radial("+ grad.matrix.tx+","+ grad.matrix.ty+", 0 ," +grad.matrix.tx+","+ grad.matrix.ty+","+ String(w/2) +");" );
					}
					
					for (var colors:int = 0; colors < grad.colors.length; colors++){
						trace( "cairo_pattern_add_color_stop_rgba (pat,"+ grad.ratios[colors]/255+","+ redPercent(grad.colors[colors])+","+ greenPercent(grad.colors[colors])+","+ bluePercent(grad.colors[colors])+","+ grad.alphas[colors]+");" );
					}
					
					trace("cairo_set_source (cr, pat);");
				}
				else if (v[i] is GraphicsStroke) {
					_type = VectorGraphics.TYPE_GraphicsStroke;
					var stroke:GraphicsStroke = GraphicsStroke(v[i]);
					if (stroke.fill) {
						gsf = GraphicsSolidFill(stroke.fill);
						trace( "cairo_set_line_width(cr, " + stroke.thickness +");" );
						trace("cairo_set_source_rgba(cr," + String(redPercent(gsf.color)) +"," + String(greenPercent(gsf.color)) +"," + String(bluePercent(gsf.color)) +"," + gsf.alpha + ");");
						
						
						//caps
						/*if (stroke.caps == CapsStyle.ROUND) {
							trace( "cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);" );
						}
						else if (stroke.caps == CapsStyle.SQUARE) {
							trace( "cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);" );
						}
						else {
							//trace( "cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);" ); //Caps are currently broken in flash so defaulting to round
							trace( "cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);" );
						}
						
						//joints
						if (stroke.joints == JointStyle.BEVEL) {
							trace( "cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);" );
						}
						else if (stroke.joints == JointStyle.ROUND) {
							trace( "cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);" );
						}
						else {
							trace( "cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);" );
						}*/
					}
				}
				else if (v[i] is GraphicsPath) {
					var gp:GraphicsPath = GraphicsPath(v[i]);
					
					var dataI:int = 0;
					
					for (var commandsI:int = 0; commandsI < gp.commands.length; commandsI++) {
						if (gp.commands[commandsI] == GraphicsPathCommand.MOVE_TO) {
							trace( "cairo_move_to(cr, "+gp.data[dataI++] +", "+gp.data[dataI++]+ ");" );
						}
						else if (gp.commands[commandsI] == GraphicsPathCommand.LINE_TO) {
							trace( "cairo_line_to(cr, "+gp.data[dataI++] +", "+gp.data[dataI++] + ");" );
						}
						else if (gp.commands[commandsI] == GraphicsPathCommand.CURVE_TO) {							
							//Converting Quadratic curve to Cubic curve
							var QP0X:Number = gp.data[dataI-2];
							var QP0Y:Number = gp.data[dataI-1];
							
							var QP1X:Number = gp.data[dataI];
							var QP1Y:Number = gp.data[dataI+1];
							
							var QP2X:Number = gp.data[dataI+2];
							var QP2Y:Number = gp.data[dataI+3];
							
							dataI+=4;
							
							var CP1X:Number = QP0X + ( TWO_THIRD * (QP1X-QP0X) );
							var CP1Y:Number = QP0Y + ( TWO_THIRD * (QP1Y-QP0Y) );
							
							var CP2X:Number = QP2X + ( TWO_THIRD * (QP1X-QP2X) );
							var CP2Y:Number = QP2Y + ( TWO_THIRD * (QP1Y-QP2Y) );
							
							trace( "cairo_curve_to(cr, "+ CP1X +", "+ CP1Y +", " + CP2X +", "+ CP2Y +", " + QP2X +", "+ QP2Y + ");" );
						}
					}
					
					if(gp.winding == GraphicsPathWinding.EVEN_ODD){
						trace( "cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);" );
					}
					else {
						trace( "cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);" );
					}
					
					//end
					if(_type == VectorGraphics.TYPE_GraphicsSolidFill){
						trace( "cairo_fill(cr);" );
					}
					else if (_type == VectorGraphics.TYPE_GraphicsGradientFill) {
						trace( "cairo_fill(cr);" );
						trace( "cairo_pattern_destroy (pat);" );
					}
					else {
						trace( "cairo_stroke(cr);" );
					}
					
				}
			}
			
			trace( "cairo_destroy(cr);" );
			trace( "cairo_surface_write_to_png(surface, \"hello.png\");" );
			trace( "cairo_surface_destroy(surface);" );
		}
		
		private function redPercent(color:int):Number {
			return (color >> 16 & 0xFF)/255;
		}
		
		private function greenPercent(color:int):Number {
			return (color >> 8 & 0xFF)/255;
		}
		
		private function bluePercent(color:int):Number {
			return (color & 0xFF)/255;
		}
		
	}

}